package com.cy.pj.sys.service.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * 通过切面学习SpringAOP中各种通知方法的应用
 */
@Order(2)
@Component
@Aspect
public class SysTimeAspect {
    @Pointcut("@annotation(com.cy.pj.sys.common.annotation.RequiredTime)")
    public void doTime(){}

    /**
     * @Before描述的方法在目标业务执行之前执行
     * 通常会在@Before方法中做一些数据的过滤或预处理
     * 所有的非@Around通知方法都可以使用JoinPoint参数
     */
    @Before("doTime()")
    public void doBefore(JoinPoint jp){
        Object[] args = jp.getArgs();
        System.out.println(Arrays.toString(args));
        System.out.println("@Before");
    }

    /**
     * @After描述的方法在目标业务执行之后执行（无论是否目标方法出现异常）
     * 通常会在@After描述的方法中进行一些资源释放操作
     */
    @After("doTime()")
    public void doAfter(){
        System.out.println("@After");
    }

    /**
     * @AfterReturning此注解描述的方法，在目标方法正常结束时执行
     */
    @AfterReturning("doTime()")
    public void doAfterReturning(){
        System.out.println("@AfterReturning");
    }

    /**
     * @AfterThrowing此注解描述的方法，在目标方法异常结束时执行
     * 例如，可以在此方法中，可以进行错误日志的记录，可以报警，发送邮件，发送短信
     */
    @AfterThrowing("doTime()")
    public void doAfterThrowing(){
        System.out.println("@AfterThrowing");
    }

    /**
     * @Around 描述的方法可以在内部通过连接点对象，手动调用目标方法，优先级最高
     * @param joinPoint 连接点对象，@Around描述的方法只能应用ProceedingJoinPoint参数
     * @return
     * @throws Throwable
     */
    @Around("doTime()")
    public Object doAround(ProceedingJoinPoint joinPoint)throws Throwable{
        System.out.println("Around.before");
        try {
            //本类其他before，其他切面的before，目标方法，当前或其他切面后续的通知方法
            Object result = joinPoint.proceed();
            System.out.println("@Around.AfterReturning");
            return result;

        }catch (Throwable e){
            e.printStackTrace();
            System.out.println("@Around.AfterThrowing");
            throw e;
        }finally {
            System.out.println("@Around.After");
        }

    }


}
